const htmlWebpackPlugin = require('html-webpack-plugin');
const MinCssExtractPlugin = require('mini-css-extract-plugin');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const ProgressBarPlugin = require('progress-bar-webpack-plugin');
const { GenerateSW, InjectManifest } = require('workbox-webpack-plugin');
const ForkWebpack = require('fork-ts-checker-webpack-plugin');
const { getThemeVariables } = require('antd/dist/theme');
const webpack = require('webpack');
const chalk = require('chalk');
const fs = require('fs');
const SpeedMeasureWebpackPlugin = require('speed-measure-webpack-plugin');
const threadLoader = require('thread-loader');

const { resolveApp, getUserConfig } = require('../utils');
const isDev = process.env.NODE_ENV === 'development';

const jsWorkerPool = {
  // options

  // 产生的 worker 的数量，默认是 (cpu 核心数 - 1)
  // 当 require('os').cpus() 是 undefined 时，则为 1
  workers: require('os').cpus().length,

  // 闲置时定时删除 worker 进程
  // 默认为 500ms
  // 可以设置为无穷大， 这样在监视模式(--watch)下可以保持 worker 持续存在
  poolTimeout: 5000,
};

threadLoader.warmup(jsWorkerPool, ['babel-loader']);

const MinCssLoader = {
  loader: MinCssExtractPlugin.loader,
  options: {
    esModule: false,
  },
};

const copyWebpackPluginPatterns = [
  {
    from: resolveApp('src/public/magic.png'),
    to: process.env.PUBLIC_PATH,
  },
  {
    from: resolveApp('src/public/favicon.ico'),
    to: process.env.PUBLIC_PATH,
  },
  {
    from: resolveApp('src/public/manifest.json'),
    to: process.env.PUBLIC_PATH,
  },
];

// 初始化环境变量
process.env.PUBLIC_PATH = '/';

// 拿取用户配置
const conf = getUserConfig();

module.exports = {
  mode: process.env.NODE_ENV,
  cache: {
    type: 'filesystem',
    buildDependencies: {
      // This makes all dependencies of this file - build dependencies
      config: [__filename],
      // By default webpack and loaders are build dependencies
    },
  },
  resolve: {
    extensions: ['.js', '.json', '.jsx', '.css', '.tsx', '.less', '.sass', '.scss', '.ts'],
    mainFields: ['jsnext:main', 'module', 'browser', 'main'],
    modules: [resolveApp('src'), 'node_modules'],
    alias: {
      '@': resolveApp('src'),
      '@utils': resolveApp('src/app/common/utils'),
      '@component': resolveApp('src/app/common/components'),
    },
  },
  output: {
    filename: isDev ? 'assets/js/[name].js' : 'assets/js/[name].[fullhash].js',
    chunkFilename: isDev ? 'assets/js/[name].js' : 'assets/js/[name].[chunkhash].js',
    publicPath: process.env.PUBLIC_PATH,
    path: resolveApp('dist'),
    clean: true,
  },
  plugins: [
    new InjectManifest({
      swSrc: resolveApp('src/sw.js'),
      swDest: 'sw.js',
      exclude: [/\.map$/, /manifest$/, /\.htaccess$/, /service-worker\.js$/, /sw\.js$/],
    }),
    new GenerateSW({
      disableDevLogs: isDev,
    }),
    new MinCssExtractPlugin({
      filename: isDev ? '[name].css' : 'assets/css/[name].[contenthash].css',
      chunkFilename: isDev ? '[id].css' : 'assets/css/[id].[contenthash].css',
      ignoreOrder: true,
      linkType: 'text/css',
    }),
    new webpack.ContextReplacementPlugin(/moment[\/\\]locale$/, /zh-cn/),
    new webpack.ids.HashedModuleIdsPlugin(),
    new htmlWebpackPlugin({
      title: conf.appName,
      template: resolveApp('/src/public/index.html'),
      inject: true,
      filename: 'index.html',
      publicPath: process.env.PUBLIC_PATH,
      minify: false,
    }),
    new webpack.DefinePlugin({
      'process.env': JSON.stringify({
        ...process.env,
      }),
    }),
    new CopyWebpackPlugin({
      patterns: copyWebpackPluginPatterns,
    }),
    new ProgressBarPlugin({
      format: `magic ${process.env.NODE_ENV} :msg [:bar] ${chalk.green.bold(
        ':percent'
      )} (:elapsed s)`,
    }),
  ],
  module: {
    rules: [
      {
        test: /\.(js|jsx|tsx|ts)/,
        include: /src/,
        use: [
          {
            loader: 'thread-loader',
            options: jsWorkerPool,
          },
          {
            loader: 'babel-loader',
            options: {
              cacheDirectory: true,
            },
          },
        ],
      },
      {
        test: /\.css$/,
        use: ['style-loader', require.resolve('css-loader')],
      },
      {
        // ant design
        test: /\.less$/,
        include: [resolveApp('node_modules/antd/'), resolveApp('node_modules/@ant-design/')],
        use: [
          'style-loader',
          MinCssLoader,
          {
            loader: require.resolve('css-loader'),
            options: {
              url: false,
            },
          },
          {
            loader: require.resolve('less-loader'),
            options: {
              lessOptions: {
                javascriptEnabled: true,
                modifyVars: getThemeVariables({
                  dark: true, // 开启暗黑模式
                }),
              },
            },
          },
        ],
      },
      {
        // src/styles
        test: /\.scss$/,
        include: resolveApp('src/styles'),
        use: ['style-loader', MinCssLoader, 'css-loader', 'sass-loader'],
      },
      {
        test: /\.(scss|sass)$/,
        include: [resolveApp('src/app')],
        exclude: [/node_modules/, resolveApp('src/styles')],
        use: [
          MinCssLoader,
          {
            loader: 'css-loader',
            options: {
              // 使用css modules
              modules: {
                mode: 'local',
                localIdentName: isDev ? '[path][name]__[local]' : '[local]-[hash:base64:5]',
              },
            },
          },
          'sass-loader',
        ],
      },
      {
        test: /\.(less)$/,
        include: [resolveApp('src/app')],
        exclude: [/node_modules/, resolveApp('src/styles')],
        use: [
          MinCssLoader,
          {
            loader: 'css-loader',
            options: {
              // 使用css modules
              modules: {
                mode: 'local',
                localIdentName: isDev ? '[path][name]__[local]' : '[local]-[hash:base64:5]',
              },
            },
          },
          {
            loader: 'less-loader',
            options: {
              lessOptions: {
                modifyVars: getThemeVariables({
                  dark: true, // 开启暗黑模式
                }),
                javascriptEnabled: true,
              },
            },
          },
        ],
      },
      {
        test: /\.(png|jpg|gif|ico)$/i,
        type: 'javascript/auto',
        generator: {
          filename: isDev ? '[name][ext]' : 'assets/img/[name][ext]',
        },
      },
      {
        test: /\.(ttf|eot|AFM)$/i,
        type: 'asset/resource',
        generator: {
          filename: isDev ? '[name][ext]' : 'assets/font/[name].[contenthash:8][ext]',
        },
      },
      {
        test: /\.svg$/,
        use: {
          loader: 'svg-sprite-loader',
          options: {
            symbolId: 'icon-[name]',
          },
        },
      },
      {
        test: /\.woff$/i,
        type: 'asset/resource',
        parser: {
          dataUrlCondition: {
            maxSize: 10 * 1024, // 10kb
          },
        },
        generator: {
          filename: isDev ? '[name][ext]' : 'assets/font/[name][ext]',
        },
        mimetype: 'application/font-woff',
      },
    ],
  },
};
